package net.m2technologies.open_arm.transport.transaction.messaging;

import net.m2technologies.open_arm.transport.transaction.AbstractTransactionMediatorImpl;

import javax.jms.*;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

/**
 * Copyright 2005 Mark Masterson<br> <br> Licensed under the Apache License, Version 2.0 (the "License");<br> you may
 * not use this file except in compliance with the License.<br> You may obtain a copy of the License at<br> <br>
 * http://www.apache.org/licenses/LICENSE-2.0<br> <br> Unless required by applicable law or agreed to in writing,
 * software<br> distributed under the License is distributed on an "AS IS" BASIS,<br> WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied.<br> See the License for the specific language governing permissions and<br>
 * limitations under the License.<br>
 * <p/>
 * <p>Description: This class outputs the information for a given transaction to JMS.</p>
 *
 * @author Mark Masterson
 * @version 0.010
 */
public class MessagingMediator extends AbstractTransactionMediatorImpl {

    private long transactionLengthInterval;
    private long updateLengthInterval;
    private boolean isBlockedEventTrap;

    private QueueConnectionFactory queueConnectionFactory;
    private Queue queue;
    private boolean isInitialized;

    public MessagingMediator(final Object transactionDelegate) {
        super(transactionDelegate);
    }

    public void setConfiguration(final Object configuration) {
        this.isInitialized = false;
        initialize(configuration);
    }

    private void initialize(final Object configuration) {
        if (!this.isInitialized) {
            if (null != configuration && configuration instanceof MessagingMediatorConfiguration) {
                try {
                    final InitialContext jndiContext
                            = new InitialContext(((MessagingMediatorConfiguration) configuration)
                            .getJndiInitialContextProperties());
                    this.queueConnectionFactory
                            = (QueueConnectionFactory) jndiContext.lookup(
                            ((MessagingMediatorConfiguration) configuration).getQueueConnectionFactoryName());
                    handleQueue(jndiContext, configuration);
                    this.transactionLengthInterval
                            = ((MessagingMediatorConfiguration) configuration).getTransactionLengthInterval();
                    this.updateLengthInterval
                            = ((MessagingMediatorConfiguration) configuration).getUpdateLengthInterval();
                    this.isBlockedEventTrap = ((MessagingMediatorConfiguration) configuration).isBlockedEventTrap();
                    this.isInitialized = true;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                throw new RuntimeException("[initialize] Configuration object null or false type!");
            }
        }
    }

    private void handleQueue(final InitialContext jndiContext, final Object configuration)
            throws NamingException, JMSException {
        try {
            this.queue
                    = (Queue) jndiContext.lookup(((MessagingMediatorConfiguration) configuration).getQueueName());
        } catch (NameNotFoundException e) {
            final QueueConnection queueConnection = this.queueConnectionFactory.createQueueConnection();
            final QueueSession queueSession = queueConnection.createQueueSession(false,
                                                                                 Session.AUTO_ACKNOWLEDGE);
            try {
                this.queue = queueSession.createQueue(((MessagingMediatorConfiguration) configuration).getQueueName());
            } finally {
                if (null != queueConnection) {
                    queueConnection.close();
                }
            }
        }
    }

    private void sendMessage(final String messageText) {
        QueueConnection queueConnection = null;
        try {
            queueConnection = this.queueConnectionFactory.createQueueConnection();
            final QueueSession queueSession = queueConnection.createQueueSession(false,
                                                                                 Session.AUTO_ACKNOWLEDGE);
            final QueueSender queueSender = queueSession.createSender(this.queue);
            final TextMessage message = queueSession.createTextMessage();
            message.setText(messageText);
            queueSender.send(message);
            queueSender.send(queueSession.createMessage());
        } catch (Exception e) {
            throw new RuntimeException(new StringBuffer().append("[sendMessage] Message: ")
                    .append(messageText).toString(), e);
        } finally {
            if (null != queueConnection) {
                try {
                    queueConnection.close();
                } catch (JMSException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    protected void doBlocked(final long tmpHandle) {
        if (this.isBlockedEventTrap) {
            sendMessage(getBlockedMessage(tmpHandle));
        }
    }

    protected void doStop(final long elapsedTime,
                          final long totalElapsedTime,
                          final int status,
                          final String diagnosticDetail) {
        if (this.transactionLengthInterval < elapsedTime || this.transactionLengthInterval < totalElapsedTime) {
            sendMessage(getStopMessage(elapsedTime, totalElapsedTime, status, diagnosticDetail));
        }
    }

    protected void doUnblocked(final long blockHandle) {
        if (this.isBlockedEventTrap) {
            sendMessage(getUnblockedMessage(blockHandle));
        }
    }

    protected void doUpdate(final long runningTime, final long totalRunningTime) {
        if (this.updateLengthInterval < runningTime || this.updateLengthInterval < totalRunningTime) {
            sendMessage(getUpdateMessage(runningTime, totalRunningTime));
        }
    }

}
